﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Xml.Linq;

namespace Dycox.Text
{
    /// <summary>
    /// 用于简体中文处理的一组辅助方法。
    /// </summary>
    public static class SimplifiedChinese
    {


        static PinyinLookup _pinyinLookup;

        /// <summary>
        /// 如果指定的文本中具有简体中文字符，将它们转换为其声母的表达方式。
        /// </summary>
        /// <param name="text">要转换的文本。</param>
        /// <param name="chageCase">更改文本中的字母大小写，包括英文字母。</param>
        /// <param name="eliminateWhitespaces">如果为<code>true</code>，将会去除源文本中的所有空白字符。</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"><paramref name="text"/>为空值。</exception>
        public static string TranslateToPinyin(string text, LetterCase chageCase, bool eliminateWhitespaces)
        {
            return TranslateToPinyin(text, chageCase, eliminateWhitespaces, false);
        }

        /// <summary>
        /// 如果指定的文本中具有简体中文字符，将它们转换为其声母的表达方式。
        /// </summary>
        /// <param name="text">要转换的文本。</param>
        /// <param name="chageCase">更改文本中的字母大小写，包括英文字母。</param>
        /// <param name="eliminateWhitespaces">如果为<code>true</code>，将会去除源文本中的所有空白字符。</param>
        /// <param name="eliminateSymbols">指示是否移除符号</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"><paramref name="text"/>为空值。</exception>
        public static string TranslateToPinyin(string text, LetterCase chageCase, bool eliminateWhitespaces, bool eliminateSymbols)
        {
            if (_pinyinLookup == null)
                _pinyinLookup = new PinyinLookup();

            return _pinyinLookup.Translate(text, chageCase, eliminateWhitespaces, eliminateSymbols);
        }

        /// <summary>
        /// 如果指定的文本中具有简体中文字符，将它们转换为其声母的表达方式。
        /// 文本中的所有字母将全部转换为大写，并去除所有空格。
        /// </summary>
        /// <param name="text">要转换的文本。</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"><paramref name="text"/>为空值。</exception>
        public static string TranslateToPinyin(string text)
        {
            return TranslateToPinyin(text, LetterCase.Upper, true);
        }

        /*

        /// <summary>
        /// 如果指定的字符是中文字符，转换为其对应声母的字符。
        /// </summary>
        /// <param name="c">要转换的单个汉字</param>
        /// <returns>拼音声母</returns>
        public static char GetPinyinChar(char c)
        {
            byte[] array;
            char zero = '\0';

            array = System.Text.Encoding.Default.GetBytes(new char[] { c });
            int i = (short)(array[0] - zero) * 0x100 + ((short)(array[1] - zero));

            if (i < 0xB0A1) return '_';
            if (i < 0xB0C5) return 'A';
            if (i < 0xB2C1) return 'B';
            if (i < 0xB4EE) return 'C';
            if (i < 0xB6EA) return 'D';
            if (i < 0xB7A2) return 'E';
            if (i < 0xB8C1) return 'F';
            if (i < 0xB9FE) return 'G';
            if (i < 0xBBF7) return 'H';
            if (i < 0xBFA6) return 'J';
            if (i < 0xC0AC) return 'K';
            if (i < 0xC2E8) return 'L';
            if (i < 0xC4C3) return 'M';
            if (i < 0xC5B6) return 'N';
            if (i < 0xC5BE) return 'O';
            if (i < 0xC6DA) return 'P';
            if (i < 0xC8BB) return 'Q';
            if (i < 0xC8F6) return 'R';
            if (i < 0xCBFA) return 'S';
            if (i < 0xCDDA) return 'T';
            if (i < 0xCEF4) return 'W';
            if (i < 0xD1B9) return 'X';
            if (i < 0xD4D1) return 'Y';
            if (i < 0xD7FA) return 'Z';

            return '_';
        }


        public static string GetPinyinCode(string strText)
        {
            if (strText == null || strText.Length == 0)
                return strText;
            System.Text.StringBuilder myStr = new System.Text.StringBuilder();
            foreach (char vChar in strText)
            {
                // 若是字母则直接输出 
                if ((vChar >= 'a' && vChar <= 'z') || (vChar >= 'A' && vChar <= 'Z'))
                    myStr.Append(char.ToUpper(vChar));
                else if ((int)vChar >= 19968 && (int)vChar <= 40869)
                {
                    // 若字符Unicode编码在编码范围则 查汉字列表进行转换输出 
                    foreach (string strList in strChineseCharList)
                    {
                        if (strList.IndexOf(vChar) > 0)
                        {
                            myStr.Append(strList[0]);
                            break;
                        }
                    }
                }
            }
            return myStr.ToString();
        }

        public static void WriteTo(string filename)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            System.Xml.XmlElement elt = null, parent;
            doc.AppendChild(doc.CreateElement("Language"));
            doc.DocumentElement.AppendChild(parent = doc.CreateElement("Pinyin"));
            char last = '\0';

            foreach (string text in strChineseCharList)
            {
                if (text[0] != last)
                {
                    last = text[0];
                    elt = doc.CreateElement("CharList");
                    elt.SetAttribute("ShengMu", last.ToString());
                    elt.InnerText = text.Substring(1);
                    parent.AppendChild(elt);
                }
                else
                    elt.InnerText += text.Substring(1);
            }

            doc.Save(filename);
            
        }
         */

        class PinyinLookup
        {
            char[][] _map;

            public PinyinLookup()
            {
                _map = new char[26][];

                XDocument doc;
                System.IO.StreamReader reader = new System.IO.StreamReader(this.GetType().Assembly.GetManifestResourceStream("Dycox.Text.SimplifiedChinese.xml"));
                
                using (reader)
                {
                    doc = XDocument.Load(reader);
                    char[] array;
                    foreach (var elt in doc.Element("Language").Element("Pinyin").Elements("CharList"))
                    {
                        char ch = elt.Attribute("ShengMu").Value[0];
                        array = elt.Value.ToCharArray();
                        Array.Sort(array);
                        _map[(int)(ch - 'A')] = array;
                    }
                    
                }
            }

            public const char NOT_FOUND = '?';

            public char Translate(char ch)
            {
                char result = NOT_FOUND;
                char[] array;
                for (int i = 0; i < 26; i++)
                {
                    array = _map[i];
                    if (array != null && Array.BinarySearch<char>(array, ch) >= 0)
                    {
                        result = (char)(65 + i);
                        break;
                    }
                }

                return result;
            }

            public string Translate(string text, LetterCase changeCase, bool eliminateWhitespaces, bool eliminateSymbols)
            {
                if (text == null)
                    throw new ArgumentNullException("text");

                char[] array = new char[text.Length];
                int j = 0;
                char t;

                foreach (int ch in text)
                {
                    t = (char)ch;
                    if (char.IsWhiteSpace(t) || ch < 32)
                    {
                        if (!eliminateWhitespaces)
                            array[j++] = t;
                        continue;
                    }

                    if (eliminateSymbols && !char.IsLetterOrDigit(t))
                        continue;

                    if (ch >= 19968 && ch <= 40869)
                        t = Translate(t);

                    if (changeCase == LetterCase.Upper)
                        t = char.ToUpper(t);
                    else if (changeCase == LetterCase.Lower)
                        t = char.ToLower(t);

                    array[j++] = t;
                }

                return new string(array, 0, j);
            }
        }
    }
}
